package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.constants.BaseConstants;
import cn.itsource.ymcc.dto.SMSSend2MQ;
import cn.itsource.ymcc.dto.SMSSendParamDto;
import cn.itsource.ymcc.exception.GlobleException;
import cn.itsource.ymcc.service.IVerifyCodeService;
import cn.itsource.ymcc.to.VerifyCode2Cache;
import cn.itsource.ymcc.util.AssertUtil;
import cn.itsource.ymcc.util.StrUtils;
import cn.itsource.ymcc.util.VerifyCodeUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;


    /**-----------------------------------------------------------------
     * Description：图片验证码
     * 1.判断参数
     * 2.创建一个图片验证码值
     * 3.把图片验证码值存储到Redis，以传入的key为key
     * 4.把验证码值画到图片中
     * 5.把图片使用base64编码成字符串
     * 6.返回base64编码成字符串
     *-----------------------------------------------------------------*/
    @Override
    public String createImageCode(String imageCodeKey) {
        //* 1.判断参数
        AssertUtil.isNotEmpty(imageCodeKey, "无效的验证码KEY，刷新重试");

        //* 2.创建一个图片验证码值
        String imgCodeValue = StrUtils.getComplexRandomString(4);

        //* 3.把图片验证码值存储到Redis，以传入的key为key
        redisTemplate.opsForValue().set(
                imageCodeKey,
                imgCodeValue,
                600 ,//过期时间10分钟
                TimeUnit.SECONDS);

        //* 4.把验证码值画到图片中
        //* 5.把图片使用base64编码成字符串
        //* 6.返回base64编码成字符串
        return VerifyCodeUtils.verifyCode(130,35 , imgCodeValue);
    }


    //1.验证参数

    //2.校验图片验证码
    //2.1.使用传入的key从redis获取图片验证码
    //2.2.redis中的图片验证码和传入的图片验证码比较

    //3.判断是否有一个未使用的手机验证码
    //4.如果有
    //4.1.从Redis获取上一次的手机验证码发送记录
    //4.2.判断上一次发送时间和当前发送时间是否过了重发时间
    //4.3.如果没过报错，过了就获取上一次手机验证码的值,
    //4.4.把上一次的验证码重发一次
    //4.5.重新存储一次验证码发送记录

    //5.如果没有
    //5.1.创建一个手机验证码
    //5.2.存储手机验证码存储到Redis
    //5.3.发送短信验证码

    //6.数据库保存验证码发送记录
    @Override
    public void sendSmsCode(SMSSendParamDto dto) {
        //1.验证参数
        String imageCode = dto.getImageCode();
        String imageCodeKey = dto.getImageCodeKey();
        String mobile = dto.getMobile();
        AssertUtil.isNotNull(imageCode,"图片验证码不可为空");
        AssertUtil.isNotNull(imageCodeKey,"无效的图片验证码，请刷新重试或联系管理员");
        AssertUtil.isPhone(
                mobile,"无效的手机号");
        //2.校验图片验证码
        //2.1.使用传入的key从redis获取图片验证码，使用传入的图片验证码的key:imageCodeKey
        String imageCodeValue = (String) redisTemplate.opsForValue().get(imageCodeKey);
        AssertUtil.isNotEmpty(imageCodeValue,"无效的图片验证码，请重新获取");
        //2.2.redis中的图片验证码和传入的图片验证码比较
        //忽略大小写比较
        AssertUtil.isEqualsIgnoreCase(imageCodeValue,imageCode,"错误的图片验证码，请重新获取");
        //手机验证码
        String smsCode = null;
        //当前时间
        Date now  = new Date();
        //key: 前缀+手机号
        String smsKey = String.format("SMS:%s",mobile );
        //3.判断是否有一个未使用的手机验证码
        VerifyCode2Cache lastSendSms = (VerifyCode2Cache) redisTemplate.opsForValue().get(smsKey);
        //4.如果有
        if(lastSendSms != null){
            //上一次发送时间
            Date sendTime = lastSendSms.getSendTime();
            if( (now.getTime() - sendTime.getTime())  / 1000 < 60){
                throw new GlobleException("发送频繁，请稍后重试");
            }
            //4.3.如果没过报错，过了就获取上一次手机验证码的值,
            smsCode = lastSendSms.getCode();
            //4.4.重新存储一次验证码发送记录
            //4.5.把上一次的验证码重发一次
        }else{
            //5.如果没有
            //5.1.创建一个手机验证码
            smsCode = StrUtils.getRandomString(6);
        }
        //5.2.存储手机验证码存储到Redis
        redisTemplate.opsForValue().set(smsKey, new VerifyCode2Cache(smsCode,mobile, now),
                10*60,TimeUnit.SECONDS);

        String smsContent =  String.format("您的验证码为 %s ,请在 %s 分钟内使用", smsCode, 10);
        log.info(smsCode);
        //手机号
        SendResult result = rocketMQTemplate.syncSend(
                BaseConstants.MessageMQ.TOPIC_MESSAGE + ":" + BaseConstants.MessageMQ.TAGS_SMS_NAME,
                JSON.toJSONString(new SMSSend2MQ(null, "注册验证码", smsContent))
        );
        log.info("短信发送到MQ",result);
    }
}
